package org.jeecg.activiti.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.jeecg.activiti.entity.*;
import org.jeecg.activiti.mapper.ActHiModelFormDataMapper;
import org.jeecg.activiti.service.IActHiModelFormDataService;
import org.jeecg.activiti.service.IActKAppendFormDataService;
import org.jeecg.activiti.service.IActKAppendFormDeploymentService;
import org.jeecg.activiti.service.IActKNodeDesignService;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TODO 表单历史数据service
 *
 * @author dousw
 * @version 1.0
 * @date 2020/9/15 11:00
 */

@Service
public class ActHiModelFormDataServiceImpl extends ServiceImpl<ActHiModelFormDataMapper, ActHiModelFormData> implements IActHiModelFormDataService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private IActKNodeDesignService actKNodeDesignService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private IActKAppendFormDeploymentService iActKAppendFormDeploymentService;

    @Autowired
    private ISysUserService iSysUserService;

    @Autowired
    private IActKAppendFormDataService iActKAppendFormDataService;

    private BpmnModel bpmnModel = null;

    private List<HistoricActivityInstance> activityFinishedList = null;

    private List<HistoricActivityInstance> tempList = null;

    @Override
    public void saveHiFormData(ActReModelFormData actReModelFormData, String processInstanceId) {
        ActHiModelFormData actHiModelFormData = new ActHiModelFormData();
        actHiModelFormData.setProcessDefinitionId(actReModelFormData.getProcessDefinitionId());
        actHiModelFormData.setFormData(actReModelFormData.getFormData());
        actHiModelFormData.setTableId(actReModelFormData.getTableId());
        actHiModelFormData.setTableName(actReModelFormData.getTableName());
        actHiModelFormData.setModelId(actReModelFormData.getModelId());
        actHiModelFormData.setFormId(actReModelFormData.getFormId());
        actHiModelFormData.setProcessInstanceId(processInstanceId);
        actHiModelFormData.setStatus(ActivitiConstant.HANDLE_STATUS_HLZ);
        actHiModelFormData.setCreateBy(actReModelFormData.getCreateBy());
        actHiModelFormData.setCreateTime(actReModelFormData.getCreateTime());
        actHiModelFormData.setUpdateBy(actReModelFormData.getUpdateBy());
        actHiModelFormData.setUpdateTime(actReModelFormData.getUpdateTime());
        actHiModelFormData.setType(actReModelFormData.getType());
        actHiModelFormData.setDataId(actReModelFormData.getDataId());
        this.baseMapper.insert(actHiModelFormData);
    }

    @Override
    public List<Map<String, Object>> handleNodeAppendForm(String taskId, String processInstanceId) {
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        List<Map<String, Object>> result = new ArrayList<>();
        if (historicTaskInstance != null) {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicTaskInstance.getProcessDefinitionId()).singleResult();
            Model model = repositoryService.createModelQuery().modelKey(processDefinition.getKey()).singleResult();
            ActKNodeDesign actKNode = actKNodeDesignService.getOne(new QueryWrapper<ActKNodeDesign>()
                    .eq("node_id", historicTaskInstance.getTaskDefinitionKey())
                    .eq("model_id", model.getId()));

            if (actKNode != null && actKNode.getIsShowAppendForm()) {
                bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());

                activityFinishedList = historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId).finished().orderByHistoricActivityInstanceEndTime().desc().list();

                tempList = new ArrayList<>();

                getReverseNodeList(historicTaskInstance.getTaskDefinitionKey());

                for (HistoricActivityInstance historicActivityInstance : tempList) {
                    Map<String, Object> tempMap = new HashMap<>();

                    String activityId = historicActivityInstance.getActivityId();
                    ActKAppendFormDeployment actKAppendFormDeployment = iActKAppendFormDeploymentService.getOne(new QueryWrapper<ActKAppendFormDeployment>()
                            .eq("node_id", activityId).eq("process_definition_id", historicTaskInstance.getProcessDefinitionId()));
                    if (actKAppendFormDeployment != null) {
                        tempMap.put("nodeId", activityId);
                        tempMap.put("formJson", actKAppendFormDeployment.getFormJson());
                        tempMap.put("nodeName", historicActivityInstance.getActivityName());
                        tempMap.put("assignee", iSysUserService.getUserByName(historicActivityInstance.getAssignee()).getRealname());

                        ActKAppendFormData actKAppendFormData = iActKAppendFormDataService.getOne(new QueryWrapper<ActKAppendFormData>()
                                .eq("node_id", activityId)
                                .eq("process_instance_id", processInstanceId)
                                .eq("task_id", historicActivityInstance.getTaskId())
                                .eq("execution_id", historicActivityInstance.getExecutionId()));

                        if (actKAppendFormData != null) {
                            tempMap.put("formData", actKAppendFormData.getFormData());
                        } else {
                            List<ActKAppendFormData> actKAppendFormDatas = iActKAppendFormDataService.list(new QueryWrapper<ActKAppendFormData>()
                                    .eq("node_id", activityId)
                                    .eq("process_instance_id", processInstanceId).orderByDesc("create_time"));
                            if (!CollectionUtils.isEmpty(actKAppendFormDatas)) {
                                tempMap.put("formData", actKAppendFormDatas.get(0).getFormData());
                            }
                        }

                        result.add(tempMap);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 逆向获取执行过的任务节点：
     * 1、子流程只能获取到本子流程节点+主流程节点，不能获取兄弟流程任务节点；
     * 2、主流程任务节点不能获取子流程任务节点；
     * @param currActivityId
     */
    private void getReverseNodeList(String currActivityId) {
        // 获取当前节点的进线，通过进线查询上个节点
        FlowNode currFlow = (FlowNode)bpmnModel.getMainProcess().getFlowElement(currActivityId);
        List<SequenceFlow> incomingFlows = currFlow.getIncomingFlows();

        // 找到上个任务节点
        for (SequenceFlow incomingFlow : incomingFlows) {
            String sourceNodeId = incomingFlow.getSourceRef();
            HistoricActivityInstance tempActivityInstance = null;
            for (HistoricActivityInstance historicActivityInstance : activityFinishedList) {
                if (historicActivityInstance.getActivityId().equals(sourceNodeId)) {
                    tempActivityInstance = historicActivityInstance;
                    break;
                }
            }

            // 解决画回头线出现死循环的问题
            if (tempList.contains(tempActivityInstance)) {
                continue;
            } else {
                if (tempActivityInstance != null) {
                    tempList.add(tempActivityInstance);
                }

                getReverseNodeList(sourceNodeId);
            }
        }
    }
}
